package cn.com.dcsgo.service.impl;

import cn.com.dcsgo.domain.dto.SysDictDataSaveDTO;
import cn.com.dcsgo.domain.dto.SysDictDataUpdateDTO;
import cn.com.dcsgo.domain.po.SysDictData;
import cn.com.dcsgo.exception.BusinessException;
import cn.com.dcsgo.mapper.SysDictDataMapper;
import cn.com.dcsgo.service.SysDictDataService;
import cn.com.dcsgo.utils.ConverterUtils;
import cn.com.dcsgo.utils.DictDataLocalCache;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Date;
import java.util.List;

/**
 * SysDictDataServiceImpl
 *
 * @author Dcsgo
 * @since 24/5/2025 上午 9:15
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SysDictDataServiceImpl implements SysDictDataService {
    private final SysDictDataMapper sysDictDataMapper;
    private final DictDataLocalCache dictDataLocalCache;

    @Override
    public int deleteByDictType(String dictType) {
        dictDataLocalCache.clear();

        int row = sysDictDataMapper.deleteByDictType(dictType);
        log.debug("deleteByDictType({}): row = {}", dictType, row);
        return row;
    }

    @Transactional(rollbackFor = {Throwable.class})
    @Override
    public int save(SysDictDataSaveDTO saveDTO) {
        dictDataLocalCache.clear();

        // 相同字典类型的字典键值键不能重复
        if (sysDictDataMapper.hasDictTypeAndDictValue(saveDTO.getDictType(), saveDTO.getDictValue())) {
            throw new BusinessException("字典类型: " + saveDTO.getDictType() + " ,"
                    + "已存在键值: " + saveDTO.getDictValue());
        }

        SysDictData saveData = new SysDictData();
        BeanUtils.copyProperties(saveDTO, saveData);
        saveData.setCreateBy(getUsername());
        saveData.setCreateTime(new Date());
        return sysDictDataMapper.insertSelective(saveData);
    }

    @Transactional(rollbackFor = {Throwable.class})
    @Override
    public int update(SysDictDataUpdateDTO updateDTO) {
        dictDataLocalCache.clear();

        SysDictData updateData = sysDictDataMapper.selectByPrimaryKey(updateDTO.getDictCode());
        Assert.notNull(updateData, "不存在编号为: " + updateDTO.getDictCode() + " 的字典数据");
        // 备份数据库中的字典类型和键值因为后续它们可能会被 syncFieldsWithNullOnEqual 方法覆盖为 null
        String oldDictType = updateData.getDictType();
        Integer oldDictValue = updateData.getDictValue();

        // ConverterUtils.syncFieldsWithNullOnEqual(source,target,excludeFieldNames)
        // 拷贝对象中的属性值，若属性值相同则将目标对象对应的属性值置 null
        ConverterUtils.syncFieldsWithNullOnEqual(updateDTO, updateData, "dictCode");
        log.debug("update({})", updateDTO);
        log.debug("syncFieldsWithNullOnEqual:updateData={}", updateData);

        // 更新字典类型或字典键值的效验
        // 同时更新字典类型和键值 新的字典键值可能会造成冲突
        // updateDTO 与 updateData 中某一属性字段经过 syncFieldsWithNullOnEqual
        // 后均不为 null 表示这个字段与数据库中的数据不同需要更新
        if (updateData.getDictType() != null && updateData.getDictValue() != null
                && sysDictDataMapper.hasDictTypeAndDictValue(updateData.getDictType(), updateData.getDictValue())) {
            throw new BusinessException("已存在字典类型: " + updateDTO.getDictType() + " 和字典键值: " + updateDTO.getDictValue());
        }
        // 只更新字典类型 旧的字典键值可能会造成冲突
        if (updateData.getDictValue() == null && updateData.getDictType() != null
                && sysDictDataMapper.hasDictTypeAndDictValue(updateData.getDictType(), oldDictValue)) {
            throw new BusinessException("已存在字典类型: " + updateData.getDictType() + " 和字典键值: " + oldDictValue);
        }
        // 只更新字典键值 新的字典键值可能会造成冲突
        if (updateData.getDictType() == null && updateData.getDictValue() != null
                && sysDictDataMapper.hasDictTypeAndDictValue(oldDictType, updateData.getDictValue())) {
            throw new BusinessException("已存在字典类型: " + oldDictType + " 和字典键值: " + updateData.getDictValue());
        }

        // 不用更新的字段置 null
        updateData.setCreateBy(null);
        updateData.setCreateTime(null);

        updateData.setUpdateBy(getUsername());
        updateData.setUpdateTime(new Date());
        return sysDictDataMapper.updateByPrimaryKeySelective(updateData);
    }

    @Override
    public SysDictData get(Long dictCode) {
        return sysDictDataMapper.selectByPrimaryKey(dictCode);
    }

    @Transactional(rollbackFor = {Throwable.class})
    @Override
    public int remove(Long dictCode) {
        dictDataLocalCache.clear();

        return sysDictDataMapper.deleteByPrimaryKey(dictCode);
    }

    @Override
    public List<SysDictData> get(String dictType) {
        // 先查询本地缓存
        List<SysDictData> cacheDictDataList = dictDataLocalCache.get(dictType);
        if (null != cacheDictDataList) {
            // 缓存中有数据，直接返回
            return cacheDictDataList;
        }
        // 缓存中没有 添加查到的数据到缓存并返回
        List<SysDictData> databaseDictDataList = sysDictDataMapper.selectByDictType(dictType);
        dictDataLocalCache.add(dictType, databaseDictDataList);
        return databaseDictDataList;
    }

    @Override
    public List<SysDictData> list() {
        return sysDictDataMapper.selectAll();
    }
}
